from Group import GroupBase
from AttributeGroup import groupClasses, ParameterGroup

class DeviceGroup(GroupBase):
    _saved_class_name = 'DeviceGroup'
    _saved_attributes = ['group_keys', 'submaster']
    _saved_child_objects = ['AttributeGroups']
    signals_to_register = ['new_parameter_group', 'member_obj_request', 'index_changed']
    def __init__(self, **kwargs):
        self.ParameterGroups = {}
        self.MainController = kwargs.get('MainController')
        super(DeviceGroup, self).__init__(**kwargs)
        if 'deserialize' not in kwargs:
            self.submaster = kwargs.get('submaster', False)
            self.AttributeGroups = {}
            #self.member_groups = {}
            self.group_keys = {}
            for key, val in groupClasses.iteritems():
                g_kwargs = self.add_osc_child(address=key)
                g_kwargs.update({'parent_group':self, 'id':'_'.join([self.id, key]), 
                                 'root_category':self.root_category.parent.subcategories['attribute'], 
                                 'submaster':self.submaster})
                self.AttributeGroups.update({key:val(**g_kwargs)})
                #self.member_groups.update({key:{}})
        if not hasattr(self, 'group_keys') or self.group_keys is None:
            self.group_keys = {}
        self.members_changed_by_osc = False
        if self.osc_enabled:
            self.add_osc_handler(callbacks={'add-member':self.on_osc_add_member, 
                                            'del-member':self.on_osc_del_member})
        devices = kwargs.get('devices', [])
        self.add_devices(devices, initializing=True)
        self.request_member_obj()
        
    def clean_members(self):
        for group in self.AttributeGroups.itervalues():
            group.clean_member_values()
        for group in self.ParameterGroups.itervalues():
            group.clean_member_values()
        keys = set()
        for key in self.group_keys.iterkeys():
            if key not in self.members:
                keys.add(key)
        for key in keys:
            del self.group_keys[key]
        
    def add_devices(self, devices, initializing=False):
        if not self.membership_lock:
            if type(devices) == list or type(devices) == tuple:
                for device in devices:
                    if initializing:
                        self.members_changed_by_osc = True
                    self.add_member(**{device.id:device})
            else:
                if initializing:
                    self.members_changed_by_osc = True
                self.add_member(**{devices.id:devices})
            
    def add_member(self, **kwargs):
        super(DeviceGroup, self).add_member(**kwargs)
        if not self.membership_lock:
            for key, val in kwargs.iteritems():
                self.group_keys.update({key:{}})
                #self.update_member_groups(key)
                member = self.members[key]
                if isinstance(val, GroupBase):
                    attrib_groups = member.AttributeGroups
                else:
                    attrib_groups = self.members[key].Groups
                for grkey, grval in attrib_groups.iteritems():
                    self.group_keys[key].update({grkey:grval.id})
                    self.AttributeGroups[grkey].add_member(**{grval.id:grval})
                for grkey, grval in val.ParameterGroups.iteritems():
                    if grval.name not in self.ParameterGroups:
                        group = ParameterGroup(attribute_name=grval.attribute_name, 
                                               parent_group=self, osc_parent_node=self.osc_node, 
                                               root_category=self.root_category.parent.subcategories['attribute'])
                        self.ParameterGroups.update({grval.name:group})
                        #print 'added param group ', group.name
                        self.group_keys[key].update({grkey:grval.id})
                        self.emit('new_parameter_group', device_group=self, param_group=group)
                    self.ParameterGroups[grval.name].add_member(**{grval.id:grval})
                #if len(self.members) > 1:
                #    bob
                if not self.members_changed_by_osc:
                    self.osc_node.send_message(address='add-member', value=key)
            self.members_changed_by_osc = False
            
    def del_member(self, key):
        if key in self.members and not self.membership_lock:
            for grkey, grval in self.AttributeGroups.iteritems():
                group_name = self.group_keys[key].get(grkey)
                if group_name:
                    grval.del_member(group_name)
            for grkey, grval in self.ParameterGroups.iteritems():
                if grkey in self.members[key].ParameterGroups:
                    grval.del_member(self.members[key].ParameterGroups[grkey].id)
            del self.group_keys[key]
            if not self.members_changed_by_osc:
                self.osc_node.send_message(address='del-member', value=key)
        super(DeviceGroup, self).del_member(key)
        self.members_changed_by_osc = False
        
    def request_member_obj(self):
        for key in self.group_keys.iterkeys():
            if key not in self.members:
                self.emit('member_obj_request', id=key, group=self)
                
    def on_osc_add_member(self, **kwargs):
        values = kwargs.get('values')
        self.members_changed_by_osc = True
        self.emit('member_obj_request', id=values[0], group=self)
        
    def on_osc_del_member(self, **kwargs):
        values = kwargs.get('values')
        self.members_changed_by_osc = True
        self.del_member(values[0])
        
    def get_values(self):
        d = {}
        for key, val in self.AttributeGroups.iteritems():
            d.update({key:val.get_values()})
        return d
        
    def get_devices(self):
        d = {}
        for key, val in self.members.iteritems():
            if getattr(val, 'base_class') == 'PatchedDevice':
                d.update({key:val})
            elif getattr(val, 'base_class') == 'Group':
                d.update(val.get_devices())
        return d
        
    def get_objects(self, **kwargs):
        d = kwargs.get('obj_dict', {})
        captured_only = kwargs.get('captured_only', False)
        for key in ['DeviceGroup', 'AttributeGroup', 'Device', 'Attribute']:
            if key not in d:
                d.update({key:{}})
        d['DeviceGroup'].update({self.id:self})
        if 'obj_dict' not in kwargs:
            kwargs['obj_dict'] = d
        for group in self.AttributeGroups.itervalues():
            group.get_objects(**kwargs)
        for key, val in self.members.iteritems():
            if val.saved_class_name == 'PatchedDevice':
                d['Device'].update({key:val})
        return d
        
    def search_for_obj(self, objkey):
        if objkey in self.AttributeGroups:
                return self.AttributeGroups[objkey]
        for group in self.AttributeGroups.itervalues():
            result = group.search_for_obj(objkey)
            if result:
                return result
        return super(DeviceGroup, self).search_for_obj(objkey)
            
    def _deserialize_child(self, d):
        for cls in groupClasses.itervalues():
            if cls._saved_class_name == d['saved_class_name']:
                g_kwargs = self.add_osc_child(address=d['saved_class_name'])
                g_kwargs.update({'parent_group':self, 'deserialize':d, 'submaster':self.submaster, 
                                 'root_category':self.root_category.parent.subcategories['attribute']})
                return cls(**g_kwargs)
